﻿using System;
using System.Collections.Generic;
using TrainGame.Model;
using TrainGame.Engine.RouteCalc;

namespace TrainGame.Engine
{
	/// <summary>
	/// Game engine (no UI aspects)
	/// </summary>
	/// <remarks>
	/// Joe: I'm working to move game engine code out of OperatingRound2.  This is starting small and should grow over time.
	/// </remarks>
	public class GameEngine
	{
		/// <summary>
		/// Finish the tile lay - make it permanent
		/// </summary>
		/// <remarks>
		/// Generated from OperatingRound2.FinishTileLay
		/// </remarks>
		/// <param name="game"></param>
		/// <param name="hex"></param>
		/// <param name="rotation">
		/// From UI, rotation is already set in the hex, but from AI it's not, so we need a non-destructive re-apply of rotation
		/// </param>
		/// <returns>true for success, false for failure</returns>
		static public bool FinishTileLay(Game game, GameboardHex hex, int rotation)
		{
			bool bReturn = false;

			if (hex != null)
			{
				// set the rotation
				hex.Rotation = rotation;

				// apply the tile lay
				hex.TransferTileRoutesToHex();
				TrackSegment.CalculateHexRoutes(hex);

				if (game.CurrentlyOperatingCompany.DeferredInitialTokenPlacement) // Check to see if the THB, or Erie, needs to place it's initial token after laying a tile.
				{
					game.CompanyMustPlaceInitialToken = true;
				}

				game.CheckForDestinations();
				bReturn = true;
			}

			return bReturn;
		}

		/// <summary>
		/// Get a list of hexes that connect to the target hex.  Used for tile lays for destinations, tokens, etc.
		/// </summary>
		/// <param name="gameboard">the gameboard to examine</param>
		/// <param name="targetHex">target hex to connect to</param>
		/// <param name="thisCompany">Current company. MAY BE NULL.
		/// If present, evaluate based on this company's connectivity (stop at blocking tokens, etc.)
		/// If null, ignore all company tokens when determining connectivity.
		/// </param>
		/// <returns>List of hex locations that are connected to target hex</returns>
		static public List<string> GetConnectedHexes(Gameboard gameboard, string targetHex, PublicCompany thisCompany)
		{
			List<string> hexVisits = new List<string>();
			GetConnectedHexes(gameboard, targetHex, thisCompany, hexVisits);
			return hexVisits;
		}

		static public void GetConnectedHexes(Gameboard gameboard, string targetHex, PublicCompany thisCompany, List<string> hexVisits)
		{
			hexVisits.Add(targetHex);

			GameboardHex hex = gameboard.GameboardHexes[targetHex];
			if (hex.Cities != null)
			{
				// we can just use RouteCalculator to do most of the work (throwing away resultant routes)
				RouteCalculator.BuildRoutes(gameboard, thisCompany, hex.Cities, thisCompany != null, false, 99, hexVisits);
			}
		}

		/// <summary>
		/// Calculate the SHORTEST distance between source and target groups of hexes, given their location strings.
		/// Same hex = 0 distance, next door hex = 1, etc.
		/// Hex locations are of the form A20, F17, etc.
		/// </summary>
		/// <param name="targetHexes">list of target hex locations</param>
		/// <param name="sourceHexes">list of hexes to evaluate</param>
		/// <returns>shortest distance in hexes</returns>
		static public int CalculateHexDistance(List<string> targetHexes, List<string> sourceHexes)
		{
			int distance = 99;
			foreach (string targetHex in targetHexes)
			{
				int d = CalculateHexDistance(targetHex, sourceHexes);
				if (d < distance)
					distance = d;
			}
			return distance;
		}

		/// <summary>
		/// Calculate the SHORTEST distance between a hex and a collection of hexes, given their location strings.
		/// Same hex = 0 distance, next door hex = 1, etc.
		/// Hex locations are of the form A20, F17, etc.
		/// </summary>
		/// <param name="targetHex">target hex location</param>
		/// <param name="hexes">list of hexes to evaluate</param>
		/// <returns>shortest distance in hexes</returns>
		static public int CalculateHexDistance(string targetHex, List<string> hexes)
		{
			int distance = 99;
			foreach (string hex in hexes)
			{
				int d = CalculateHexDistance(targetHex, hex);
				if (d < distance)
					distance = d;
			}
			return distance;
		}

		/// <summary>
		/// Calculate the distance between two hexes, given their location strings.
		/// Same hex = 0 distance, next door hex = 1, etc.
		/// Hex locations are of the form A20, F17, etc.
		/// </summary>
		/// <param name="hexLoc1">first hex location</param>
		/// <param name="hexLoc2">second hex location</param>
		/// <returns>distance in hexes</returns>
		static public int CalculateHexDistance(string hexLoc1, string hexLoc2)
		{
			if ((hexLoc1.Length >= 2) && (hexLoc2.Length >= 2))
			{
				int col1 = hexLoc1[0] - 'A';
				int row1 = int.Parse(hexLoc1.Substring(1));
				int col2 = hexLoc2[0] - 'A';
				int row2 = int.Parse(hexLoc2.Substring(1));

				int colDist = Math.Abs (col2 - col1);
				int rowDist = Math.Abs (row2 - row1);

				int diff = colDist + Math.Max(0, (rowDist - colDist) / 2);
				return diff;
			}
			return 99;	// can't figure it out
		}
	}
}
